<!DOCTYPE html>
<!-- Defines the document type and HTML language -->
<html lang="en">
<head>
     <!-- Sets the character encoding for the document to UTF-8 -->
    <meta charset="UTF-8">
       <!-- Ensures the page is responsive and adjusts its layout to the viewport width -->
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
     <!-- Sets the title of the webpage -->
    <title>Toronto - Dual Map Comparison</title>
     <!-- Loads the MapLibre GL JS library -->
    <script src="https://unpkg.com/maplibre-gl/dist/maplibre-gl.js"></script>
     <!-- Loads the MapLibre GL CSS stylesheet -->
    <link href="https://unpkg.com/maplibre-gl/dist/maplibre-gl.css" rel="stylesheet" />
    <style>
        /* CSS styles for the HTML elements */
        /* Makes map occupy screen */
        html,
        body {
            margin: 0;
            padding: 0;
            height: 100%;
            width: 100%;
            font-family: Arial, sans-serif;
        }

        .map-container {
            display: flex;
            height: 100vh;
            width: 100%;
        }

        .map-box {
            width: 50%;
            height: 100%;
            position: relative;
        }
        /* Creates two maps */
        #map-left,
        #map-right {
            width: 100%;
            height: 100%;
        }
        /* Creates style sheet for map titles */

        .map-title {
            position: absolute;
            top: 10px;
            left: 50%;
            transform: translateX(-50%);
            background: rgba(255, 255, 255, 0.8);
            padding: 5px 10px;
            border-radius: 5px;
            font-weight: bold;
            font-size: 16px;
            z-index: 1;
        }
        /* */

        .map-overlay {
            position: absolute;
            top: 50px;
            left: 10px;
            background: white;
            padding: 10px;
            border-radius: 8px;
            box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
            z-index: 1;
            display: flex;
            flex-direction: column;
            gap: 5px;
        }

        .map-overlay label {
            display: flex;
            align-items: center;
            gap: 5px;
            font-size: 14px;
            cursor: pointer;
        }

        .map-overlay input[type="checkbox"] {
            accent-color: #007bff;
            width: 16px;
            height: 16px;
        }

        /* Welcome Panel Styling */
        .welcome-panel {
            position: fixed;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            background: rgba(0, 0, 0, 0.7);
            /* Semi-transparent background */
            display: flex;
            justify-content: center;
            align-items: center;
            z-index: 2;
        }

        .welcome-content {
            background: white;
            padding: 20px;
            text-align: center;
            border-radius: 8px;
            max-width: 500px;
            box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.2);
        }

        .welcome-content h2 {
            margin-bottom: 10px;
        }

        .welcome-button {
            margin-top: 15px;
            padding: 8px 16px;
            border: none;
            background-color: #007bff;
            color: white;
            font-size: 16px;
            cursor: pointer;
            border-radius: 5px;
        }

        .welcome-button:hover {
            background-color: #0056b3;
        }
        /* Hide a map information box */

        .maplibregl-ctrl-bottom-right {
            z-index: 1;
        }
    </style>
</head>

<body>

    <!-- Welcome Panel -->
    <div class="welcome-panel" id="welcomePanel">
        <div class="welcome-content">
            <h2>Welcome to the Toronto Interactive Map 🏙️</h2>
            <p>This map was made through data acquired from Toronto Open Source 2021. 
                I hope that this map can aid comparisons and visualizations of the relationship between immigration and subsidized housing for research.
            </p>
            <p>Click on a neighborhood to see details.</p>
            <button class="welcome-button" onclick="closeWelcomePanel()">Start Exploring 🚀</button>
        </div>
    </div>
<!-- Map -->
    <div class="map-container">
        <div class="map-box">
            <div class="map-title">Low Income & Immigrant Population</div>
            <div id="map-left"></div>
             <!-- Map layer selection boxes -->
            <div class="map-overlay">
                <label>
                    <input type="checkbox" value="lowincome"
                        onchange="toggleLayer(mapLeft, 'lowincome-layer', this.checked)" checked>
                    Low Income
                </label>
                <label>
                    <input type="checkbox" value="immigrant"
                        onchange="toggleLayer(mapLeft, 'immigrant-layer', this.checked)">
                    Immigrant Population
                </label>
                <label>
                    <input type="checkbox" onchange="toggleLayer(mapRight, 'subsidized-layer', this.checked)" checked>
                    Subsidized Housing
                </label>
            </div>
        </div>
        <div class="map-box">
            <div class="map-title">Subsidized Housing Programs</div>
            <div id="map-right"></div>
        </div>
    </div>

    <script>
         //close welcome panel
        function closeWelcomePanel() {
            document.getElementById('welcomePanel').style.display = 'none';
        }

        const geojsonPath = "assets/neighborhood-sub-20250105.geojson";
        const housingGeojsonPath = "assets/sh.geojson";
        let mapLeft = null;
        let mapRight = null;
        let syncing = false;
         //load everything after window loads
        window.onload = function () {
             //define two maps
            mapLeft = new maplibregl.Map({
                container: "map-left",
                style: "https://basemaps.cartocdn.com/gl/positron-gl-style/style.json",
                center: [-79.3832, 43.6532],
                zoom: 12
            });

            mapRight = new maplibregl.Map({
                container: "map-right",
                style: "https://basemaps.cartocdn.com/gl/positron-gl-style/style.json",
                center: [-79.3832, 43.6532],
                zoom: 12
            });
             //load navigation panel
            mapRight.addControl(new maplibregl.NavigationControl());
             //synchronize two maps
            function syncMaps(map1, map2) {
                map1.on("moveend", () => {
                    if (!syncing) {
                        syncing = true;
                        setTimeout(() => {
                            map2.jumpTo({ center: map1.getCenter(), zoom: map1.getZoom() });
                            syncing = false;
                        }, 50);
                    }
                });

                map2.on("moveend", () => {
                    if (!syncing) {
                        syncing = true;
                        setTimeout(() => {
                            map1.jumpTo({ center: map2.getCenter(), zoom: map2.getZoom() });
                            syncing = false;
                        }, 50);
                    }
                });
            }

            syncMaps(mapLeft, mapRight);
             //load data
            fetch(geojsonPath)
                .then(response => response.json())
                .then(data => {
                     //pre-process data for loading

                    let lowincomeValues = data.features.map(f => f.properties.lowincomeper).filter(v => v !== null && v !== undefined);
                    const minLowIncome = Math.min(...lowincomeValues);
                    const maxLowIncome = Math.max(...lowincomeValues);

                    data.features.forEach(feature => {
                        if (feature.properties.immigrants !== null && feature.properties.totalpop !== null) {
                            feature.properties.immigrantper = feature.properties.immigrants / feature.properties.totalpop * 100;
                        } else {
                            feature.properties.immigrantper = null;
                        }
                    });

                    let immigrantValues = data.features.map(f => f.properties.immigrantper).filter(v => v !== null && v !== undefined);
                    const minImmigrants = Math.min(...immigrantValues);
                    const maxImmigrants = Math.max(...immigrantValues);

                    let subsidizedValues = data.features.map(f => f.properties["num-subsidized"]).filter(v => v !== null && v !== undefined);
                    const minSubsidized = Math.min(...subsidizedValues);
                    const maxSubsidized = Math.max(...subsidizedValues);
                     //add two data sources
                    mapLeft.addSource("neighborhoods", { type: "geojson", data });
                    mapRight.addSource("neighborhoods", { type: "geojson", data });
                     //add low-income layer
                    mapLeft.addLayer({
                        id: 'lowincome-layer',
                        type: 'fill',
                        source: 'neighborhoods',
                        paint: {
                            'fill-color': [
                                'interpolate', ['linear'], ['get', 'lowincomeper'],
                                minLowIncome, '#d0e1f9',
                                (minLowIncome + maxLowIncome) / 2, '#4a90e2',
                                maxLowIncome, '#003f5c'
                            ],
                            'fill-opacity': 0.7
                        },
                        layout: { 'visibility': 'visible' }
                    }, 'watername_ocean');
                     //add immigrant layer
                    mapLeft.addLayer({
                        id: 'immigrant-layer',
                        type: 'fill',
                        source: 'neighborhoods',
                        paint: {
                            'fill-color': [
                                'interpolate', ['linear'], ['get', 'immigrantper'],
                                minImmigrants, '#d3f9d8',
                                (minImmigrants + maxImmigrants) / 2, '#63c37c',
                                maxImmigrants, '#004c1f'
                            ],
                            'fill-opacity': 0.7
                        },
                        layout: { 'visibility': 'none' }
                    }, 'watername_ocean');
                     //add subsidized housing layer
                    mapRight.addLayer({
                        id: 'subsidized-layer',
                        type: 'fill',
                        source: 'neighborhoods',
                        paint: {
                            'fill-color': [
                                'interpolate', ['linear'], ['get', 'num-subsidized'],
                                minSubsidized, '#ffe0b2',
                                (minSubsidized + maxSubsidized) / 2, '#ff9800',
                                maxSubsidized, '#e65100'
                            ],
                            'fill-opacity': 0.7
                        },
                        layout: { 'visibility': 'visible' }
                    }, 'watername_ocean');


                    //add borders
                    mapLeft.addLayer({
                        id: "border-layer",
                        type: "fill",
                        source: "neighborhoods",
                        paint: {
                            "fill-color": "transparent",
                            "fill-outline-color": "#ffffff"
                        }
                    }, 'watername_ocean');

                    mapRight.addLayer({
                        id: "border-layer",
                        type: "fill",
                        source: "neighborhoods",
                        paint: {
                            "fill-color": "transparent",
                            "fill-outline-color": "#ffffff"
                        }
                    }, 'watername_ocean');



                    //add click function to borders
                    mapLeft.on("click", "border-layer", (e) => {
                        if (!e.features || e.features.length === 0) return;

                        const properties = e.features[0].properties;
                        const neighborhoodName = properties.name || "Unknown";
                        const neighborhoodDesc = properties.desc || "Unknown";


                        const encodedNeighborhood = encodeURIComponent(neighborhoodDesc);

                         //default profile link of each neighborhood 
                        const profileURL = `https://www.toronto.ca/city-government/data-research-maps/neighbourhoods-communities/neighbourhood-profiles/find-your-neighbourhood/neighbourhood-profile-detail/?id=NeighbourhoodProfiles-CityofToronto/Snapshot110&title=Neighbourhood%20Profile%20Data#type=filtered&filter=Select+a+Neighbourhood&value=${encodedNeighborhood}`;
                         //handle pop-up
                        new maplibregl.Popup()
                            .setLngLat(e.lngLat)
                            .setHTML(`
                                <div style="font-family: Arial, sans-serif; max-width: 260px; padding: 8px; line-height: 1.4;">
                                    <h3 style="margin: 5px 0; font-size: 16px; font-weight: bold; color: #333;">
                                        ${neighborhoodName}
                                    </h3>
                                    <p><strong>Total Population:</strong> ${properties.totalpop || "N/A"}</p>
                                    <p><strong>Lower Income Rate:</strong> ${(properties.lowincomeper || 0).toFixed(2)}%</p>
                                    <p><strong>Immigrant Population:</strong> ${properties.immigrants || "N/A"}</p>
                                    <p><strong>Subsidized Housing Programs:</strong> ${properties["num-subsidized"] || "N/A"}</p>
                                    <a href="${profileURL}" target="_blank" style="
                                        display: inline-block;
                                        margin-top: 8px;
                                        padding: 6px 12px;
                                        background-color: #007bff;
                                        color: white;
                                        text-decoration: none;
                                        border-radius: 4px;
                                        font-size: 14px;
                                        text-align: center;
                                    ">
                                        Read More
                                    </a>
                                </div>`).addTo(mapLeft);


                    });
                    //changers cursor to pointer
                    mapLeft.on('mouseenter', 'border-layer', () => {
                        mapLeft.getCanvas().style.cursor = 'pointer';
                    });
                    mapLeft.on('mouseleave', 'border-layer', () => {
                        mapLeft.getCanvas().style.cursor = '';
                    });




                });



          //load subsidized housing data
            fetch(housingGeojsonPath)
                .then(response => response.json())
                .then(data => {


                    layers = mapRight.getStyle().layers;
                    let firstSymbolId;
                    for (let i = 0; i < layers.length; i++) {
                        if (layers[i].type === 'symbol') {
                            firstSymbolId = layers[i].id;
                            break;
                        }
                    }
                    //add subsidized housing data to map
                    mapRight.addSource("subsidized-housing", { type: "geojson", data });
                    //add subsidized housing points
                    mapRight.addLayer({
                        id: "housing-points",
                        type: "circle",
                        source: "subsidized-housing",
                        paint: {
                            "circle-radius": 6,
                            "circle-color": "#ff0000",
                            "circle-stroke-width": 1,
                            "circle-stroke-color": "#fff"
                        },
                        layout: { visibility: "visible" },
                    });
                     //make each program clickable
                    mapRight.on("click", "housing-points", (e) => {
                        e.originalEvent.stopPropagation(); 

                        const properties = e.features[0].properties;
                        new maplibregl.Popup({ closeOnClick: true })
                            .setLngLat(e.lngLat)
                            .setHTML(`
                                <div style="
                                    font-family: Arial, sans-serif; 
                                    padding: 10px;
                                    min-width: 200px; 
                                    max-width: 500px; 
                                    word-break: break-word; 
                                ">
                                    <h3 style="
                                        margin: 5px 0; 
                                        font-size: 16px; 
                                        font-weight: bold; 
                                        color: #333;
                                    ">
                                        ${properties["Building Complex Name"] || "N/A"}
                                    </h3>
                                    
                                    <p><strong>Wheelchair Accessible:</strong> ${properties["Wheelchair Accessible Building"] || "N/A"}</p>
                                    <p><strong>Accessible Units:</strong> ${properties["Wheelchair Accessible Units"] || "N/A"}</p>
                                    <p><strong>Income Limit:</strong> ${properties["Household Income Limit"] || "N/A"}</p>
                                    <p><strong>Available Units:</strong> ${properties["Units Available in the Last 12 Months"] || "N/A"}</p>
                                    <p><strong>Total Subsidized Units:</strong> ${properties["Number of Subsidized Units"] || "N/A"}</p>
                                </div>
                            `).addTo(mapRight);
                    });
                     //make cursor a pointer
                    mapRight.on('mouseenter', 'housing-points', () => {
                        mapRight.getCanvas().style.cursor = 'pointer';
                    });
                    mapRight.on('mouseleave', 'housing-points', () => {
                        mapRight.getCanvas().style.cursor = '';
                    });





                });
             //hide information panel on the right
            var maplogos = document.getElementsByClassName("maplibregl-ctrl-bottom-right");
            if (maplogos.length > 0) {
                maplogos[0].style.display = "none";
            }
        };
         //make layer toggleable
        function toggleLayer(map, layerId, isChecked) {
            const lowIncomeLayer = "lowincome-layer";
            const immigrantLayer = "immigrant-layer";


            const lowIncomeCheckbox = document.querySelector("input[value='lowincome']");
            const immigrantCheckbox = document.querySelector("input[value='immigrant']");

            if (layerId === lowIncomeLayer) {

                map.setLayoutProperty(lowIncomeLayer, "visibility", isChecked ? "visible" : "none");

                if (isChecked) {
                    map.setLayoutProperty(immigrantLayer, "visibility", "none");

                    immigrantCheckbox.checked = false;
                }
            } else if (layerId === immigrantLayer) {

                map.setLayoutProperty(immigrantLayer, "visibility", isChecked ? "visible" : "none");

                if (isChecked) {
                    map.setLayoutProperty(lowIncomeLayer, "visibility", "none");

                    lowIncomeCheckbox.checked = false;
                }
            }
        }
    </script>
</body>

</html>
